/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace CSharpKit.Native
{
    /// <summary>
    /// 本地依赖 - ND
    /// </summary>
    public abstract class NativeDependency
    {
        protected NativeDependency() { }


        /// <summary>
        /// 本地依赖库绝对路径, NDAP
        /// </summary>
        /// <remarks>
        /// 在App.config中设置
        ///     <appSettings>
        ///     <add key = "NativeDependencyAbsolutePath" value="d:\bin" />
        ///     </appSettings>
        /// </remarks>
        protected const string NativePathSetting = "NativeDependencyAbsolutePath";

        // 定义三方库相对路径，用于添加环境路径（PATH）
        // 库路径：./_lib_dir/_lib_folder/_lib_version/_lib_x86/xxx.dll
        // 库路径：./_lib_dir/_lib_folder/_lib_version/_lib_x64/xxx.dll
        //
        protected const string _lib_dir = "ThirdParty";
        protected const string _fld_x86 = "x86";
        protected const string _fld_x64 = "x64";

        // 在派生类中设置参数
        //

        /// <summary>
        /// 动态库所在文件夹
        /// </summary>
        protected static string _lib_folder = "动态库所在文件夹";
        /// <summary>
        /// 动态库版本文件夹
        /// </summary>
        protected static string _lib_version = "动态库版本文件夹";

        static string _NativeDllPath = "";
        /// <summary>
        /// 动态库路径
        /// </summary>
        public static string NativeDllPath => _NativeDllPath;


        // 库路径
        // 
        private static string LIB_PATH_X86 => Path.Combine(_lib_dir, _lib_folder, _lib_version, _fld_x86);
        private static string LIB_PATH_X64 => Path.Combine(_lib_dir, _lib_folder, _lib_version, _fld_x64);


        /// <summary>
        /// 外部依赖库相对路径
        /// </summary>
        public static void ResolvePathToExternalDependencies()
        {
            // 取得 Dll 路径
            if (!GetDllPathFromAppConfig(out _NativeDllPath))
            {
                GetDllPathFromAssembly(out _NativeDllPath);
            }

            // 添加路径到系统环境中
            AddPathStringToEnvironment(_NativeDllPath);

#if DEBUG
            Debug.WriteLine(string.Format("NativeDllPath = {0}", _NativeDllPath));
#endif
        }


        [Obsolete("no use", true)]
        static void ResolvePathToExternalDependencies_bak()
        {
            // 取得 Dll 路径
            if (!GetDllPathFromAppConfig(out string nativeDllPath))
            {
                GetDllPathFromAssembly(out nativeDllPath);
            }

            // 添加路径到系统环境中
            AddPathStringToEnvironment(nativeDllPath);

#if DEBUG
            Debug.WriteLine(string.Format("NativeDllPath = {0}", nativeDllPath));
#endif
        }

        /// <summary>
        /// 从 AppConfig 取得库路径
        /// </summary>
        /// <param name="dllPath"></param>
        /// <returns></returns>
        private static bool GetDllPathFromAppConfig(out string dllPath)
        {
            dllPath = string.Empty;
            return false;
            /*
            dllPath = string.Empty;

            try
            {
                if (ConfigurationManager.AppSettings.Count <= 0)
                    return false;

                string pathFromAppSettings = ConfigurationManager.AppSettings[NativePathSetting].ToString();
                if (string.IsNullOrEmpty(pathFromAppSettings))
                {
                    return false;
                }

                foreach (var c in Path.GetInvalidPathChars())
                {
                    if (pathFromAppSettings.Contains(new string(c, 1)))
                    {
                        return false;
                    }
                }

                dllPath = pathFromAppSettings;
                return true;
            }
            catch
            {
                return false;
            }
            */
        }

        private static void GetDllPathFromAssembly(out string dllPath)
        {
            // Environment.Is64BitOperatingSystem;
            // 
            switch (IntPtr.Size)
            {
                case 4: // 32位
                    dllPath = Path.Combine(Path.GetDirectoryName(GetAssemblyName()), LIB_PATH_X86);
                    break;

                case 8: // 64位
                    dllPath = Path.Combine(Path.GetDirectoryName(GetAssemblyName()), LIB_PATH_X64);
                    break;

                default:
                    throw new NotImplementedException();
            }
        }

        private static string GetAssemblyName()
        {
            // 程序集绝对路径
            // 转换为非转义表示形式
            // string myPath = new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).AbsolutePath;
            string myPath = new Uri(Assembly.GetExecutingAssembly().Location).AbsolutePath;
            myPath = Uri.UnescapeDataString(myPath);

            return myPath;
        }

        /// <summary>
        /// 添加路径到环境
        /// </summary>
        /// <param name="aPath">库路径</param>
        private static void AddPathStringToEnvironment(string aPath)
        {
            try
            {
                // 环境变量 - PATH
                string envPath = Environment.GetEnvironmentVariable("PATH");
                if (!envPath.Contains(aPath))
                {
                    Environment.SetEnvironmentVariable("PATH", aPath + ";" + envPath);
                }
            }
            catch (System.Security.SecurityException)
            {
                System.Diagnostics.Debug.WriteLine("Changing PATH not allowed");
            }
        }

        //}}@@@
    }




}
